android: strip BOOT_COMPLETED receivers from merged manifest (#4832)#7158
android: strip BOOT_COMPLETED receivers from merged manifest (#4832)#7158
Conversation
Google Play rejects targetSdk 35 builds when the merged AndroidManifest wires BOOT_COMPLETED receivers to restricted foreground service types (location, microphone, dataSync, camera, mediaPlayback, phoneCall, mediaProjection). flutter_foreground_task and flutter_background_service both inject such receivers via their plugin manifests and neither has shipped a fix (Dev-hwang/flutter_foreground_task#356, ekasetiawans/flutter_background_service#517 and #518 are open). We never opt into autostart (autoRunOnBoot/autoStartOnBoot are false), so removing the receivers and the dead RECEIVE_BOOT_COMPLETED permission via tools:node="remove" is a no-op at runtime and clears the Play scan. Verified by running com.android.tools.build:manifest-merger 32.2.0 locally against the app + plugin manifests with --remove-tools-declarations: the resulting merged manifest has no BOOT_COMPLETED action, no RECEIVE_BOOT_COMPLETED permission, and no boot receiver entries, while the location/microphone/connectedDevice foreground service declarations remain intact. Fixes #4832
|
@morpheus review — Approved ✅ Standard Android manifest merger workaround. |
Greptile SummaryThis PR fixes a Google Play Store rejection for targetSdk-35 builds by stripping two plugin-injected
Confidence Score: 5/5Safe to merge — the change is a targeted manifest-merger override that removes boot-autostart receivers that were never used at runtime. The diff touches only three manifest declarations: it marks the unused RECEIVE_BOOT_COMPLETED permission and two plugin-injected boot receivers for removal via tools:node="remove". The app already disables both autoRunOnBoot and autoStartOnBoot in Dart, so removing the receivers has no effect on runtime behaviour. The PR author ran the manifest-merger tool locally and confirmed zero BOOT_COMPLETED occurrences in the merged output. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[AGP Manifest Merger] --> B{Process app AndroidManifest.xml}
B --> C[RECEIVE_BOOT_COMPLETED\ntools:node=remove]
B --> D[RebootReceiver stub\ntools:node=remove]
B --> E[BootReceiver stub\ntools:node=remove]
F[flutter_foreground_task manifest] --> G[RebootReceiver\nBOOT_COMPLETED intent-filter]
H[flutter_background_service manifest] --> I[BootReceiver\nBOOT_COMPLETED intent-filter]
J[App manifest] --> K[RECEIVE_BOOT_COMPLETED\npermission]
G -->|merger conflict resolution| D
I -->|merger conflict resolution| E
K -->|merger conflict resolution| C
C -->|removed| L[Merged AndroidManifest.xml]
D -->|removed| L
E -->|removed| L
L --> M[0 BOOT_COMPLETED occurrences\n✓ Play Store accepted]
Reviews (2): Last reviewed commit: "android: strip BOOT_COMPLETED receivers ..." | Re-trigger Greptile |
| <receiver | ||
| android:name="com.pravera.flutter_foreground_task.service.RebootReceiver" | ||
| tools:node="remove" /> | ||
| <receiver | ||
| android:name="id.flutter.flutter_background_service.BootReceiver" | ||
| tools:node="remove" /> |
There was a problem hiding this comment.
Silent failure if boot-autostart is ever re-enabled
These tools:node="remove" stubs permanently strip the boot receivers from the merged manifest. If a future developer sets autoRunOnBoot: true in foreground.dart or autoStartOnBoot: true in services.dart, the receivers will already be gone and the auto-start will silently do nothing on reboot — no crash, no log, just dead configuration. A short inline comment explaining that these override plugin-injected boot receivers (and referencing the disabled autoRunOnBoot/autoStartOnBoot options) would prevent this from becoming a mystery bug.
| <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" | ||
| tools:node="remove" /> |
There was a problem hiding this comment.
Plugin library manifests may re-contribute the permission
tools:node="remove" on the app-level <uses-permission> removes the app's own declaration and, in the merger's conflict-resolution pass, prevents lower-priority manifests from winning for the same key. The PR's own verification run (grep -c RECEIVE_BOOT_COMPLETED merged-fixed-clean.xml → 0) confirms this works end-to-end. No action needed — this note is purely for reviewer awareness, and the test plan steps with aapt2 dump on the produced APK will provide definitive confirmation.
|
Hey @mdmohsin7 👋 Thank you so much for taking the time to contribute to Omi! We truly appreciate you putting in the effort to submit this pull request. After careful review, we've decided not to merge this particular PR. Please don't take this personally — we genuinely try to merge as many contributions as possible, but sometimes we have to make tough calls based on:
Your contribution is still valuable to us, and we'd love to see you contribute again in the future! If you'd like feedback on how to improve this PR or want to discuss alternative approaches, please don't hesitate to reach out. Thank you for being part of the Omi community! 💜 |
|
#7159 closed the wrong pr |
Summary
Google Play rejects targetSdk-35 builds when the merged AndroidManifest wires
BOOT_COMPLETEDreceivers to restricted foreground service types (location,microphone,dataSync,camera,mediaPlayback,phoneCall,mediaProjection).Two of our plugins inject such receivers via their plugin manifests:
flutter_foreground_task9.1.0RebootReceiverForegroundServicelocationflutter_background_service_android6.3.0BootReceiverBackgroundServicemicrophoneWe never opt into autostart at runtime (
autoRunOnBoot: falseinapp/lib/utils/audio/foreground.dart:129,autoStartOnBoot: falseinapp/lib/services/services.dart:148), so removing the receivers + the deadRECEIVE_BOOT_COMPLETEDpermission viatools:node="remove"is a no-op at runtime and clears the Play scan.Why not upgrade the plugins
Both upstreams have unfixed open issues and no shipped workaround:
Dev-hwang/flutter_foreground_task— issue #356 open since 2025-07-31, closed #335 without a fix. Latest version 9.2.2 still ships theRebootReceiverdeclaration.ekasetiawans/flutter_background_service— issues #517 and #518 open since 2025-07-04. Latest 6.3.1 still ships theBootReceiverdeclaration.Verification
Ran
com.android.tools.build:manifest-merger32.2.0 locally against the app'sAndroidManifest.xmlplus both plugin manifests, with--remove-tools-declarationsto mirror what AGP does:Baseline (current
main) merged manifest contains:<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /><receiver android:name="com.pravera.flutter_foreground_task.service.RebootReceiver">with<action android:name="android.intent.action.BOOT_COMPLETED"/><receiver android:name="id.flutter.flutter_background_service.BootReceiver">with<action android:name="android.intent.action.BOOT_COMPLETED"/>With this PR applied the merged manifest contains:
BOOT_COMPLETEDRECEIVE_BOOT_COMPLETEDlocation,microphone,connectedDevice)RestartReceiverandWatchdogReceiver(no boot intent-filter) preservedTest plan
caleb/android15-boot-receiver-strip(android-internal-auto) — confirm gradle assembles with no manifest-merger conflictaapt2 dump xmltree base.apk --file AndroidManifest.xml, confirm noBOOT_COMPLETEDaction and noRECEIVE_BOOT_COMPLETEDpermission